const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

const workboxWebpackPlugin = require('workbox-webpack-plugin')

// 复用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
]

/**
 * thread-loader
 * 一般给babel-loader用
 * 使用多个loader需要使用数组use
 *
 */
module.exports = {
  entry: './src/js/index.js',
  output: {
    // 增加构建目录的hash值，防止服务器强缓存
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      /**
       * 正常来讲，一个文件只能被一个loader处理
       * 当一个文件要被多个loader处理时，一定要指定loader的执行先后顺序
       * 先执行eslint后执行babel
       *
       * eslint并不认识全局变量，如window
       */
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        // 让eslint优先执行
        enforce: 'pre',
        options: {
          fix: true
        }
      },
      {
        /**
         * oneOf: 提升构建速度，防止文件被多个loader处理
         * 一下loader只会匹配一个，提升loader的处理性能，命中即不再匹配
         * 注意：不能有两个配置处理同一个类型文件（如babel和eslint都处理js文件，需要把eslint提取出去，放到数组内）
         */
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },

          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              /**
               * 开启多进程打包
               * 进程开启是有时间的600ms, 进程通信也需要时间
               * 即打包时间小的不需要多进程打包
               * 只有工作消耗时间比较长，才需要多进程打包（babel干的活多，js代码多）
               */
              // 'thread-loader',
              {
                loader: 'thread-loader',
                options: {
                  workers: 2  //修改cpu核数
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        useBuiltIns: 'usage',
                        corejs: {
                          version: 3
                        },
                        targets: {
                          chrome: '60',
                          firefox: '60',
                          ie: '9',
                          safari: '10',
                          edge: '17'
                        }
                      }
                    ]
                  ],
                  // 开启babel缓存
                  // 第二次构建时，会读取之前的缓存
                  cacheDirectory: true
                }
              }
            ]
          },
          {
            test: /\.(png|jpg|gif)$/,
            use: [
              {
                loader: 'url-loader', // url-loader 依赖file-loader,是对file-loader的一些优化（压缩图片）
                options: {
                  limit: 8196,
                  name: 'img/[name].[hash:8].[ext]',
                  esModule: false,
                  outputPath: 'imgs' // 打包到imgs目录下
                }
              }
            ]
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(css|js|html|less|jpg|png|gif)$/,
            loader: 'file-loader',
            options: {
              outputPath: 'media',
              name: '[hash: 10].[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: 'css/main.[contenthash:10].css'
    }),
    new optimizeCssAssetsWebpackPlugin(),
    new workboxWebpackPlugin.GenerateSW({
      /**
       * 1. 帮助serviceworker快速启动
       * 2. 删除旧的serviceworker
       *
       * 功能：生成一个servicework配置文件
       *
       */
      clientsClaim: true,
      skipWaiting: true
    })
  ],
  mode: 'production',
  devtool: 'source-map'
}
